package org.oos.dao.lists;

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;

import org.oos.atom.AtomEntity;
import org.oos.atom.AtomFeed;
import org.oos.dao.Dao;
import org.oos.dao.exceptions.ReadException;
import org.oos.dao.options.PageOptions;

import static org.oos.dao.options.OptionsMap.FINDERS.*;
import org.oos.lists.DynamicList;

/**
 * 
 * 
 * 
 * @author pablo.gonzalez@11870.com
 * 
 * @param <Entity>
 * @param <Feed>
 */
public class ReadOnlyDynamicList<Entity extends AtomEntity, Feed extends AtomFeed<Entity>>
		extends AbstractList<Entity> implements DynamicList<Entity> {

	private static final long serialVersionUID = 3873304282632821435L;

	// protected Feed firstFeed;
	protected int totalSize = 0;
	protected int basePageSize = 0;
	protected List<Entity> buffer = new ArrayList<Entity>();
	protected Dao<Entity, Feed> dao;
	private List<Entity> all;

	public static final int MAX_FEED_SIZE = 200;

	/**
	 * 
	 * Create a new ReadOnly List from the provided feed (first page) as well a
	 * {@link Dao} to provide the following pages.
	 * 
	 * @param dao
	 * @param feed
	 */
	public ReadOnlyDynamicList(Dao<Entity, Feed> dao, Feed feed) {
		super();
		if (feed.getEntries() != null) {
			this.totalSize = feed.getTotalResults();
			this.basePageSize = feed.getItemsPerPage();
			this.buffer.addAll(feed.getEntries());
		}
		this.dao = dao;
	}

	@Override
	public List<Entity> getAll() {
		if (all == null) {
			all = new ArrayList<Entity>(this);
		}
		return all;
	}

	@Override
	public void loadAll() throws ReadException {
		buffer.clear();
		int pageCount = totalSize / MAX_FEED_SIZE;
		if (totalSize % MAX_FEED_SIZE != 0) {
			pageCount += 1;
		}
		PageOptions pageOptions = PAGE_OPTIONS.get(dao.getOptions());
		int originalPageSize = pageOptions.getPageSize();
		pageOptions.setPageSize(MAX_FEED_SIZE);
		for (int i = 1; i <= pageCount; i++) {
			buffer.addAll(dao.readFeed(i).getEntries());
		}
		pageOptions.setPageSize(originalPageSize);
	}

	@Override
	public Entity get(int index) {
		try {
			if (index < 0 || index >= totalSize) {
				throw new IndexOutOfBoundsException();
			}

			int pageSize = basePageSize;

			if (all != null) {
				return all.get(index);
			}

			if (index >= buffer.size()) {

				// int start = ((buffer.size() + 1) / pageSize) + 1;
				// int end = ((index + 1) / pageSize) + 1;
				// buffer.addAll(dao.readFeed(start, end).getEntries());

				while (buffer.size() <= index) {
					int page = ((buffer.size() + 1) / pageSize) + 1;
					buffer.addAll(dao.readFeed(page).getEntries());
				}
			}
			return buffer.get(index);
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	@Override
	public int size() {
		return totalSize;
	}

	@SuppressWarnings("unchecked")
	@Override
	public ReadOnlyDynamicList<Entity, Feed> clone()
			throws CloneNotSupportedException {
		return (ReadOnlyDynamicList<Entity, Feed>) super.clone();
	}

}
